#include "syntax_parser.h"


#include "main_container.h"
extern MainContainer * CompilerData;

// <define_body_statements> ~ <define_body_statement> <define_body_statements>  {trace, int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream, NAME, numeric, start, process, enum, const, public, private, protected, static, abstract, override, virtual, final}
// <define_body_statements> ~ ? {}}
void Parser::Parse_DefineBodyStatements(SyntaxTreeNode * parent)
{
	LexicUnit currentUnit;
	// get current lexic unit
	do 
	{
		currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);

		if((currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordInt ||currentUnit.subtype == KeywordTrace ||
			currentUnit.subtype == KeywordFloat || currentUnit.subtype == KeywordBool ||
			currentUnit.subtype == KeywordState || currentUnit.subtype == KeywordTime ||
			currentUnit.subtype == KeywordVoid || currentUnit.subtype == KeywordFacility ||
			currentUnit.subtype == KeywordStorage || currentUnit.subtype == KeywordQueue ||
			currentUnit.subtype == KeywordADTable || currentUnit.subtype == KeywordGroup ||
			currentUnit.subtype == KeywordOutputStream ||currentUnit.subtype == KeywordNumeric ||
			currentUnit.subtype == KeywordStart || currentUnit.subtype == KeywordProcess ||
			currentUnit.subtype == KeywordEnum || currentUnit.subtype == KeywordConst ||
			currentUnit.subtype == KeywordPublic ||currentUnit.subtype == KeywordPrivate ||
			currentUnit.subtype == KeywordProtected ||currentUnit.subtype == KeywordStatic ||
			currentUnit.subtype == KeywordAbstract ||currentUnit.subtype == KeywordOverride ||
			currentUnit.subtype == KeywordVirtual ||currentUnit.subtype == KeywordFinal)) ||
			(currentUnit.type == LUTypeIdentifier))
		{
			// write type of production in this node
			parent->Production = Gr_DefineBodyStatements__DefineBodyStatement_DefineBodyStatements;

			// process nonterminal symbol <define_body_statement> 
			SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
			parent->Nodes->Add(newNode0);
			Parse_DefineBodyStatement(newNode0);
		}

		else if( currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterRightCurlyBrace )
		{
			// write type of production in this node
			parent->Production = Gr_DefineBodyStatements__DefineBodyStatement_DefineBodyStatements;;
			break;
		}
		else
		{
		// ERROR has been found
		// REPORT ERROR
		// MAKE LOGICAL RECOVERING
		this->CurrentLexicPosition++;
		break;
		}
	}while (1);
}

// <define_body_statement> ~ <field_definition>  {trace, int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream, NAME, const, public, private, protected, static}
// <define_body_statement> ~ <property_definition>  {int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream, NAME, public, protected, private, static, abstract, override, virtual, final}
// <define_body_statement> ~ <method_definition>  {numeric, start, process, int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream, NAME, abstract, virtual, public, private, protected, override, static, final}
// <define_body_statement> ~ <enum_definition>  {enum}
void Parser::Parse_DefineBodyStatement(SyntaxTreeNode * parent)
{
	LexicUnit currentUnit;
	// get current lexic unit
	currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
	
	if (currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordConst||currentUnit.subtype == KeywordTrace)) 
	{
		// write type of production in this node
		parent->Production = Gr_DefineBodyStatement__FieldDefinition;

		// process nonterminal symbol <field_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_FieldDefinition(newNode0);
	}
	else if(currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordNumeric ||
		currentUnit.subtype == KeywordStart || currentUnit.subtype == KeywordProcess))
	{
		// write type of production in this node
		parent->Production = Gr_DefineBodyStatement__MethodDefinition;

		// process nonterminal symbol <method_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_MethodDefinition(newNode0);
	}

	else if( currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordEnum )
	{
		// write type of production in this node
		parent->Production =Gr_DefineBodyStatement__EnumDefinition;

		// process nonterminal symbol <enum_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_EnumDefinition(newNode0);
	}
	else if(((currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordInt ||
		currentUnit.subtype == KeywordFloat || currentUnit.subtype == KeywordBool ||
		currentUnit.subtype == KeywordState || currentUnit.subtype == KeywordTime ||
		currentUnit.subtype == KeywordVoid || currentUnit.subtype == KeywordFacility ||
		currentUnit.subtype == KeywordStorage || currentUnit.subtype == KeywordQueue ||
		currentUnit.subtype == KeywordADTable || currentUnit.subtype == KeywordGroup ||
		currentUnit.subtype == KeywordOutputStream || currentUnit.subtype == KeywordPublic || 
		currentUnit.subtype == KeywordPrivate || currentUnit.subtype == KeywordProtected || 
		currentUnit.subtype == KeywordStatic)) || (currentUnit.type == LUTypeIdentifier))
		&& isFieldProduction (this->CurrentLexicPosition) )
	{
		// write type of production in this node
		parent->Production = Gr_DefineBodyStatement__FieldDefinition;

		// process nonterminal symbol <field_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_FieldDefinition(newNode0);

	}

	else if(((currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordInt ||
		currentUnit.subtype == KeywordFloat || currentUnit.subtype == KeywordBool ||
		currentUnit.subtype == KeywordState || currentUnit.subtype == KeywordTime ||
		currentUnit.subtype == KeywordVoid || currentUnit.subtype == KeywordFacility ||
		currentUnit.subtype == KeywordStorage || currentUnit.subtype == KeywordQueue ||
		currentUnit.subtype == KeywordADTable || currentUnit.subtype == KeywordGroup ||
		currentUnit.subtype == KeywordOutputStream || currentUnit.subtype == KeywordPublic ||
		currentUnit.subtype == KeywordPrivate || currentUnit.subtype == KeywordProtected || 
		currentUnit.subtype == KeywordStatic ||currentUnit.subtype == KeywordAbstract ||
		currentUnit.subtype == KeywordOverride || currentUnit.subtype == KeywordVirtual ||
		currentUnit.subtype == KeywordFinal)) || (currentUnit.type == LUTypeIdentifier))
		&& isPropertyProduction (this->CurrentLexicPosition))
	{
		// write type of production in this node
		parent->Production = Gr_DefineBodyStatement__PropertyDefinition;

		// process nonterminal symbol <property_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_PropertyDefinition(newNode0);

	}
	else if(((currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordInt || 
		currentUnit.subtype == KeywordFloat || currentUnit.subtype == KeywordBool || 
		currentUnit.subtype == KeywordState || currentUnit.subtype == KeywordTime || 
		currentUnit.subtype == KeywordVoid || currentUnit.subtype == KeywordFacility || 
		currentUnit.subtype == KeywordStorage || currentUnit.subtype == KeywordQueue || 
		currentUnit.subtype == KeywordADTable || currentUnit.subtype == KeywordGroup || 
		currentUnit.subtype == KeywordOutputStream || currentUnit.subtype == KeywordAbstract || 
		currentUnit.subtype == KeywordVirtual || currentUnit.subtype == KeywordPublic || 
		currentUnit.subtype == KeywordPrivate || currentUnit.subtype == KeywordProtected || 
		currentUnit.subtype == KeywordOverride || currentUnit.subtype == KeywordStatic || 
		currentUnit.subtype == KeywordFinal)) || (currentUnit.type == LUTypeIdentifier))
		&& isMethodProduction (this->CurrentLexicPosition))
	{
		// write type of production in this node
		parent->Production = Gr_DefineBodyStatement__MethodDefinition;

		// process nonterminal symbol <method_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_MethodDefinition(newNode0);
	}
	else
	{
	// ERROR has been found
	// REPORT ERROR
	// MAKE LOGICAL RECOVERING
	} 
}